/*****************************************************************************
 *  CommLayerLib - TCPClient.java
 *  Copyright (C) 2012  Matteo Piscitelli
 *  E-mail: matteo@picciux.it
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  For further info, check http://code.google.com/p/java-comm-layer/
 *
 *  SVN: $Id: TCPClient.java 32 2012-10-09 18:20:32Z picciux@gmail.com $
 *  
 *****************************************************************************/

package it.picciux.commlayer.net;

import it.picciux.commlayer.CommLayerException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public abstract class TCPClient  {
	/*
	private class MonitorReader extends DataReader {
		
		public MonitorReader() {
			//super(is);
		}
		
		protected boolean readData() {
			return false;
		}
		
		public void run() {
			while (isRunning()) {
				try {
					if ( in.read() == -1) terminate();					
				} catch (IOException e) {
					terminate();
				}
			}
			
			in = null;
			out = null;
			notifyListeners(DISCONNECTED, "");
		}

		@Override
		protected void delay() {
		}

		@Override
		public void setThreadData() {
		}
	}
	*/
	
	protected boolean connected = false;
	protected String address;
	protected int port;
	
	public boolean isConnected() {
		return connected;
	}
	
	protected abstract void retrieveRemoteAddress();
	
	public String getRemoteDescription() {
		if (address == null || port == 0) retrieveRemoteAddress();
		
		return address + ":" + Integer.toString(port);
	}
	
	/**
	 * Blocks until connected or exception
	 * @param url
	 * @throws CommLayerException
	 */
	public void connect(String url) throws CommLayerException {
		int i = url.indexOf(':');
		if (i == -1) 
			throw new CommLayerException("URL is missing port", NetworkLayer.MALFORMED_URL);
		
		String a = url.substring(0, i);
		int p = Integer.parseInt(url.substring(i + 1), 10);
		
		connect(a, p);
	}

	/**
	 * Blocks until connected or exception
	 * @param address
	 * @param port
	 * @throws CommLayerException
	 */
	public void connect(String address, int port) throws CommLayerException {
		if (connected) return;
		
		if (address == null || address.length() == 0) 
			throw new CommLayerException("Missing destination host", NetworkLayer.MALFORMED_URL);
			
		if (port == 0) 
			throw new CommLayerException("Missing destination port", NetworkLayer.MALFORMED_URL);
		
		this.address = address;
		this.port = port;
		connected = false;
		
		tryConnection();

		connected = true;
		
		monitor();
	}
	
	public abstract void disconnect();

	public abstract InputStream getInputStream() throws IOException;
	public abstract OutputStream getOutputStream() throws IOException;
	
	protected abstract boolean tryConnection() throws CommLayerException;
	protected abstract void destroy();
	
	/**
	 * Blocks until connection drops
	 */
	public void monitor() {
		boolean m = true;
		
		InputStream s = null;
		
		try {
			s = getInputStream();
		} catch (IOException e1) {
			m = false;
		}

		while(m) {
			try {
				if ( s.read() == -1) m = false;					
			} catch (IOException e) {
				m = false;
			}			
		}
		
		connected = false;
	}
	
}